package sicnu.cs.ich.ich.rest;

import com.github.pagehelper.PageInfo;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.web.bind.annotation.*;
import sicnu.cs.ich.api.common.Constants;
import sicnu.cs.ich.api.common.ResultInfo;
import sicnu.cs.ich.api.common.annotations.OperLog;
import sicnu.cs.ich.api.common.annotations.OperLogConfig;
import sicnu.cs.ich.api.common.enums.OperEnum;
import sicnu.cs.ich.api.domain.dto.*;
import sicnu.cs.ich.api.domain.entity.Ich;
import sicnu.cs.ich.api.domain.entity.IchProvince;
import sicnu.cs.ich.api.domain.form.PageParam;
import sicnu.cs.ich.api.domain.vo.IchVO;
import sicnu.cs.ich.common.services.impl.RedisService;
import sicnu.cs.ich.common.util.RequestUtil;
import sicnu.cs.ich.common.util.ResultInfoUtil;
import sicnu.cs.ich.ich.feign.IchRankingClient;
import sicnu.cs.ich.ich.service.IIchService;
import sicnu.cs.ich.ich.service.impl.BloomFilterService;
import sicnu.cs.ich.token.security.util.SecurityUtil;

import java.util.List;
import java.util.Map;
import java.util.PriorityQueue;
import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;

import static sicnu.cs.ich.api.common.Constants.MAX_ICH_COUNT;


/**
 * @author 蔡珂
 */
@Slf4j
@RestController
@RequestMapping("/auth/ichs")
@RequiredArgsConstructor
@OperLogConfig("AUTH-非遗模块")
public class AuthIchResource {

    private final IIchService ichService;
    private final RedisService redisService;
    private final IchRankingClient rankingClient;
    private final BloomFilterService bloomFilterService;
    private final SecurityUtil securityUtil;
    private final static String ICH_LIKE_PREFIX = Constants.REDIS_ICH_LIKE;

    /**
     * 各省非遗数量
     */
    @GetMapping("/chinaInfo")
    public ResultInfo<List<IchProvinceDTO>> getProvinceIchInfos() {
        return ResultInfoUtil.buildSuccess(ichService.getProvinceIch());
    }

    /**
     * 获取省级下面的非遗信息
     * @param province 省号
     */
    @GetMapping("/provinceInfo/{province}")
    public ResultInfo<List<IchCityDTO>> getCityIchInfos(@PathVariable Integer province) {
        return ResultInfoUtil.buildSuccess(ichService.getCityIch(province));
    }

    /**
     * 获取非遗 By 类型
     * @param province 省号
     * @param typeId 类型号
     * @param param 页参数
     */
    @PostMapping(value = {"/type/{province}/{typeId}", "/type/{typeId}"})
    public ResultInfo<PageInfo<IchDTO>> getIchsByType(@PathVariable(required = false) Integer province, @PathVariable("typeId") Integer typeId,
                                                      @RequestBody PageParam param) {
        PageInfo<IchDTO> ichs = ichService.getIchsByTypeId(typeId, param, province);
        return ResultInfoUtil.buildSuccess(ichs);
    }

    /**
     * 获取非遗 By 非遗id
     * @param ichId 非遗id
     */
    @GetMapping("/{ichId}")
    public ResultInfo<Map<String, Object>> getIchById(@PathVariable("ichId") Integer ichId) throws InterruptedException {
        // 布隆过滤器筛选
        if (!bloomFilterService.ichIdExist(ichId)) {
            return ResultInfoUtil.buildError("无id为" + ichId + "的非遗。");
        }
        // 查询非遗
        Ich ich = ichService.getIchById(ichId);
        if (ich == null) {
            return ResultInfoUtil.buildError("无id为" + ichId + "的非遗。");
        }
        // 构造返回非遗视图
        IchVO ichVO = new IchVO();
        BeanUtils.copyProperties(ich, ichVO);
        // 获取该非遗的点赞个数
        var num = redisService.getBitCount(ICH_LIKE_PREFIX + ichId);
        ichVO.setLikeTotal(num + ich.getHot());
        ichVO.setLikeToday(num);
        // 暂时不用
        //ichVO.setType(ichService.getType(ichVO.getTypeId()));
        var uid = securityUtil.getCurrentUserId();
        if (uid != -1) {
            ichVO.setAlreadyLike(redisService.getBit(ICH_LIKE_PREFIX + ichId, uid));
            ichVO.setAlreadyCollected(ichService.isCollected(ichId));
        }
        // 获取相似非遗
        List<IchDTO> similarIchs = ichService.getSimilarIchsByType(ichId, ichVO.getTypeId()
                , Integer.parseInt(ichVO.getProvince()));
        return ResultInfoUtil.buildSuccess(Map.of("ichVo", ichVO, "similarIchs", similarIchs));
    }

    /**
     * 获取非遗类别热度榜
     */
    @GetMapping("/type/hit")
    public ResultInfo<List<Integer>> getTypeHit() throws InterruptedException {
        List<Integer> list = redisService.getList(Constants.REDIS_RANK_ICH_HIT, 0, -1).stream().map(e -> (Integer) e).collect(Collectors.toList());
        if (list.isEmpty()) {
            return ResultInfoUtil.buildSuccess(rankingClient.sortAndGet());
        }
        return ResultInfoUtil.buildSuccess(list);
    }

    /**
     * 从非遗热度榜中获取size个非遗
     * @param size 获取数量
     */
    @GetMapping("/hit")
    public ResultInfo<List<IchDTO>> getHitIchs(@RequestParam("size") Integer size) throws InterruptedException {
        if (size > MAX_ICH_COUNT) {
            return ResultInfoUtil.buildError("size超过最大获取数：" + MAX_ICH_COUNT);
        }
        var ichIds = rankingClient.getHitIchs(size);
        List<IchDTO> ichs = ichService.getIchByList(ichIds);
        return ResultInfoUtil.buildSuccess(ichs);
    }

    /**
     * 【后台用】手动触发非遗热度排序并返回
     */
    @GetMapping("/hit/refresh")
    @OperLog(type = OperEnum.UPDATE)
    public ResultInfo<PriorityQueue<IchHitDTO>> testIchHitsMap() {
        return rankingClient.sortAndReturn();
    }

    /**
     * 清除ich版块下的所有缓存
     */
    @DeleteMapping("/cache")
    @OperLog(type = OperEnum.DELETE)
    public ResultInfo<Void> clearIchCache() {
        ichService.clearCache();
        return ResultInfoUtil.buildSuccess();
    }

    /**
     * 获取(今日)某省下热度排行榜前多少位
     * @param province 省号
     * @param preNum 前几位
     */
    @GetMapping("/province/rank/{province}/{preNum}")
    public ResultInfo<List<IchHotDTO>> getProvinceRankList(@PathVariable String province, @PathVariable Integer preNum) {
        var hotRank = ichService.getProvinceIchHotDTO(province,preNum);
        return ResultInfoUtil.buildSuccess(hotRank);
    }

    /**
     * 获取省非遗信息
     * @param province 省号
     */
    @GetMapping("/province/{province}")
    public ResultInfo<IchProvince> getProvince(@PathVariable Integer province) {
        IchProvince ichProvince = ichService.ichProvince(province);
        return ResultInfoUtil.buildSuccess(ichProvince);
    }

    /**
     * 地区下各个类型的数量
     * @param regionId 地区码
     * @return
     */
    @GetMapping("/allTypeNum/{regionId}")
    public ResultInfo<List<IchTypeDTO>> getAllTypeNum(@PathVariable Integer regionId) {
        return ResultInfoUtil.buildSuccess(ichService.getTypeCountOfRegion(regionId));
    }

    /**
     * 【弃用】获取非遗的 本日 点赞助力数量
     * @param ichId 非遗id
     * @return
     */
    @Deprecated
    @GetMapping("/like/today/{ichId}")
    public ResultInfo<Long> getIchLikingNumForToday(@PathVariable("ichId") Integer ichId) {
        var num = redisService.getBitCount(ICH_LIKE_PREFIX + ichId);
        return ResultInfoUtil.buildSuccess(num);
    }

    /**
     * 【弃用】获取非遗的 总的 点赞助力数量
     * @param ichId 非遗id
     * @return
     */
    @Deprecated
    @GetMapping("/like/{ichId}")
    public ResultInfo<Integer> getIchLikingTotalNum(@PathVariable("ichId") Integer ichId) {
        var num = ichService.getIchLikeNumById(ichId);
        return ResultInfoUtil.buildSuccess(num);
    }

    /**
     * 获取省下某个类型的热度榜
     * @param province 省码
     * @param typeId 类型
     */
    @GetMapping(value = {"/province/typeHot/{province}/{typeId}", "/province/typeHot/{province}"})
    public ResultInfo<Object> getTypeHot(@PathVariable Integer province, @PathVariable(required = false) Integer typeId) throws ExecutionException {
        var provinceDTO = ichService.getProvinceTypeHotIchs(province);
        if (typeId != null) {
            IchTypeDTO ret = null;
            for (IchTypeDTO typeDTO : provinceDTO.getTypeDTOS()) {
                if (typeDTO.getId().equals(typeId)) {
                    ret = typeDTO;
                    break;
                }
            }
            return ResultInfoUtil.buildSuccess(ret);
        }
        return ResultInfoUtil.buildSuccess(provinceDTO);
    }
}